import {
    boolType,
    numType,
    strType,
    dateType,
    regexpType,
    symbolType,
    funType,
    tranverseTypes,
    setType,
    mapType
} from '@/config/cloneType'
/**
 * @description 判断是否为外链(该项目以外的链接)
 * @param {*} path
 * @returns {boolean}
 */
export function isExternal (path) {
    return /^(https?:|mailto:|tel:)/.test(path)
}

/**
 * @description 判断是否是名称(包含中文字符，英文大小写,数字)
 * @param {*} value
 * @returns {boolean}
 */
export function isName (value) {
    const reg = /^[\u4e00-\u9fa5a-zA-Z0-9]+$/
    return reg.test(value)
}

/**
 * @description 判断是否为数字且最多两位小数
 * @param {*} str
 * @returns  {boolean}
 */
export function isTwoPointNum (str) {
    const reg = /^\d+(\.d{1,2})?$/
    return reg.test(str)
}

/**
 * @description  判断经度 -180.0～+180.0（整数部分为0～180，必须输入1到5位小数）
 * @param {*} str
 * @returns  {boolean}
 */
export function isLongitude (str) {
    const reg = /^[-|+]?(0?\d{1,2}\.\d{1,5}|1[0-7]?\d{1}\.\d{1,5}|180\.0{1,5})$/
    return reg.test(str)
}

/**
 * @description  判断纬度 -90.0～+90.0（整数部分为0～90，必须输入1到5位小数）
 * @param {*} str
 * @returns  {boolean}
 */

export function isLatitude (str) {
    const reg = /^[-|+]?([0-8]?\d{1}\.\d{1,5}|90\.0{1,5})$/
    return reg.test(str)
}

/**
 * @description  创建a链接跳转
 * @param {*} url
 * @returns  
 */

export function openUrl (url) {
    const link = document.createElement('a')
    link.style.display = 'none'
    link.setAttribute('target', '_blank')
    link.href = url
    document.body.appendChild(link)
    link.click()
    document.body.removeChild(link)
}

/*
* 深拷贝
* @param {Object} obj 要拷贝的对象
* @param {Map} map 用于存储循环引用对象的地址
*/

// 只要参数不是null，且类型结果不是object和function，那说明这个参数一定不是对象类型
const isObject = (obj) => {
    const type = typeof obj;
    return obj !== null && (type === 'object' || type === 'function')
}

const getObjectType = (obj) => {
        return Object.prototype.toString.call(obj);
}

// 拷贝正则
const cloneRegExp = (obj) => {
    const {
        resource, // 匹配文本
        flags,   // 正则修饰符
        lastIndex  // 指定下次匹配从什么位置开始
    } = obj;
    const obj_ = new RegExp(resource, flags);
    obj_.lastIndex = lastIndex;
    return obj_;
}

// 拷贝不便于遍历的对象类型
const cloneOtherType = (obj, type) => {
    switch(type) {
        case boolType:
        case numType:
        case strType:
        case dateType:
            return new obj.constructor(obj.valueOf());
        case symbolType:
            return Object(obj.valueOf());
        case regexpType:
            return cloneRegExp(obj);
        case funType:
            return obj;
    }
}

export function deepClone (obj = {}, map = new Map())  {
    // 如果不是对象直接返回
    if(!isObject(obj)) {
        return obj;
    }

    // 获取当前参数的对象类型
    const objType = getObjectType(obj);

    let obj_;
    if (tranverseTypes.includes(objType)) {
        // 如果是可遍历类型
        // 根据 consructor 找到要拷贝对象的原始构造器，初始化创建对应空对象
        obj_ = new obj.constructor();
    } else {
        return cloneOtherType(obj, objType);
    }

    // 之前有拷贝obj自身过吗
    if(map.has(obj)) {
        // 返回之前的结果出去
        return map.get(obj)
    }
    // 存储当前要拷贝的对象，解决拷贝循环引用对象自身的问题
    map.set(obj, obj_);

    // 拷贝Set 使用add(value)方法添加
    if(objType === setType) {
        obj.forEach((val, key) => {
            obj_.add(deepClone(val, map))
        })
    }

    // 拷贝Map 使用set(key, value) 方法添加
    if(objType === mapType) {
        obj.forEach((val, key) => {
            obj_.set(key, deepClone(val, map))
        })
    }

    // 如果是 [] 或者 {}
    for (let i in obj) {
        obj_[i] = deepClone(obj[i], map)
    }

    return obj_;
}

